package functionroots.methods;

import functionroots.primitives.MaximumIterationsException;
import functionroots.primitives.RealFunction;
import functionroots.primitives.RootFinder;

/**
 * Implementa o método da bissecção para a obtenção de zeros de funções de uma
 * variável real. A classe de dados iniciais utilizados é IntervalData, que
 * especifica contem um limite inferior e um limite superior de um intervalo
 * real.
 * @author orion
 */
public class Bissection extends RootFinder<IntervalData> {

    /**
     * Instancia o método da bissecção com uma função, precisão e número máximo
     * de iterações pré-definidos.
     * @param function a função alvo.
     * @param precision a precisão pretendida.
     * @param maxIterations o número máximo de iterações.
     */
    public Bissection(RealFunction function, double precision, long maxIterations) {
        super(function, precision, maxIterations);
    }

    /**
     * Instancia o método da bissecção com uma função e precisão pré-definidas.
     * @param function a função alvo.
     * @param precision a precisão pretendida.
     */
    public Bissection(RealFunction function, double precision) {
        super(function, precision);
    }

    public double scan(IntervalData data) throws MaximumIterationsException {
        double a = data.a, b = data.b;
        if (getFunction().value(a) * getFunction().value(b) >= 0) {
            throw new IllegalArgumentException("Invalid interval specified.");
        }
        double root = (a + b) / 2;
        for (int i = 0; i < getMaxIterations(); i++) {
            if (getFunction().value(root) == 0) {
                return root;
            } else if (Math.abs(b - a) < getPrecision()) {
                return root;
            } else if (getFunction().value(a) * getFunction().value(root) < 0) {
                b = root;
            } else {
                a = root;
            }
            root = (a + b) / 2;
        }
        throw new MaximumIterationsException(this, data, root);
    }
}
